﻿using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Airthmetic
{
    /// <summary>
    /// 传入参数
    /// </summary>
    public class ReconstructInput
    {
        //Pattern
        /// <summary> 条纹光栅图片数量 </summary>
        public int PatternCount = 42;
        /// <summary> 条纹光栅垂直向深度 </summary>
        public int HorizontalDepth = 10;
        /// <summary> 条纹光栅水平向深度 </summary>
        public int VerticalDepth = 10;

        /// <summary> 原图组数量 </summary>
        public int capImageCount { get { return capImagePath.Count; } }
        /// <summary> 解码成功数量 </summary>
        public int finImageCount { get { int flag = 0; foreach (bool fi in finImageFlag) { if (fi) flag++; } return flag; } }

        //Capture
        /// <summary> 图像文件夹(原图) </summary>
        public List<string> capImagePath = new List<string>();

        //Calibration
        /// <summary> 标定数据 </summary>
        public CalibrationResult caliResults = new CalibrationResult();

        //Reconstruct
        /// <summary> 图像文件夹2(Reconstruct\\预处理后2) </summary>
        public List<string> preImage2Path = new List<string>();
        /// <summary> 是否成功（解码） </summary>
        public List<bool> finImageFlag = new List<bool>();
    }

    /// <summary>
    /// 重建参数
    /// </summary>
    [Serializable]
    public class ReconstructParam
    {
        /// <summary> 解码：二值化阈值 </summary>
        public int Threshold = 40;
        /// <summary> 解码：黑光功率比(投影仪) Black light power ratio (projector) </summary>
        public double BlackLightPowerRatio = 0.5;
        /// <summary> 解码：最小直射光分量 Minimum direct light component </summary>
        public byte MinDirectLightComponent = 5;

        ///// <summary> 标定：单应性窗口，以角点为中心作矩形取点 </summary>
        //public int HomographyWindow = 30;

        /// <summary> 重建：最大射线距离 </summary>
        public double MaxRayDistance = 100;
    }

    /// <summary>
    /// 重建数据
    /// </summary>
    [Serializable]
    public class ReconstructData
    {
        ///// <summary> 是否重建成功 </summary>
        //public bool isOK = false;

        ///// <summary> 点云路径 </summary>
        //public List<string> PlyPath = new List<string>();

        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            //isOK = false;
            //PlyPath.Clear();
        }
    }

    /// <summary>
    /// 点云类
    /// </summary>
    public class PointCloud
    {
        /// <summary>  </summary>
        public List<int[]> indexList = new List<int[]>();
        /// <summary>  </summary>
        public Mat points = null;
        /// <summary>  </summary>
        public Mat colors = null;
        /// <summary>  </summary>
        public Mat normals = null;

        /// <summary>
        /// 初始化点云数据
        /// </summary>
        /// <param name="rows"></param>
        /// <param name="cols"></param>
        public void init_points(int rows, int cols)
        {
            indexList.Clear();

            points = new Mat(rows, cols, MatType.CV_32FC3);
            colors = Mat.Zeros(rows, cols, MatType.CV_8UC3);
            normals = new Mat(rows, cols, MatType.CV_32FC3);

            long size = rows * cols;
            Point3f Point3fNaN = new Point3f();
            Point3fNaN.X = float.NaN; Point3fNaN.Y = float.NaN; Point3fNaN.Z = float.NaN;
            Vec3b Vec3b255 = new Vec3b();
            Vec3b255[0] = 255; Vec3b255[1] = 255; Vec3b255[2] = 255;

            for (int h = 0; h < rows; h++)
            {
                for (int w = 0; w < cols; w++)
                {
                    points.Set<Point3f>(h, w, Point3fNaN);
                    colors.Set<Vec3b>(h, w, Vec3b255);
                    normals.Set<Point3f>(h, w, Point3fNaN);
                }
            }
        }
        /// <summary>
        /// 获取点云
        /// </summary>
        /// <param name="sb"></param>
        public void GetPly(ref StringBuilder sb)
        {
            foreach (var point in indexList)
            {
                sb.AppendLine(GetPly(point[0], point[1]));
            }
        }
        /// <summary>
        /// 获取点云
        /// </summary>
        /// <param name="y"></param>
        /// <param name="x"></param>
        /// <returns></returns>
        public string GetPly(int y, int x)
        {
            Point3f p = points.At<Point3f>(y, x);
            Vec3b c = colors.At<Vec3b>(y, x);
            Point3f n = normals.At<Point3f>(y, x);
            return $"{p.X} {p.Y} {p.Z} \r\n{n.X} {n.Y} {n.Z} \r\n{c.Item0} {c.Item1} {c.Item2}";
        }
        /// <summary>
        /// 获取点云
        /// </summary>
        /// <param name="sb"></param>
        public void GetPly2(ref StringBuilder sb)
        {
            foreach (var point in indexList)
            {
                sb.AppendLine(GetPly2(point[0], point[1]));
            }
        }
        /// <summary>
        /// 获取点云
        /// </summary>
        /// <param name="y"></param>
        /// <param name="x"></param>
        /// <returns></returns>
        public string GetPly2(int y, int x)
        {
            Point3f p = points.At<Point3f>(y, x);
            Vec3b c = colors.At<Vec3b>(y, x);
            return $"{p.X} {p.Y} {p.Z} \r\n{c.Item0} {c.Item1} {c.Item2}";
        }
    }
}
